#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <windows.h>
#include "config.h"
#include "logging.h"
#include "telnet.h"

#pragma comment(lib, "ws2_32.lib")

// The size of the receiving message buffer
#define BUFF_BYTE 128

/* F U N K T I O N  P R O T O T Y P E S */
static void telnetAuthorize(SOCKET telnet);
static void telnetCommands(SOCKET telnet);
static void printAdminMesage(SOCKET telnet);
static BOOL parseBuffer(SOCKET socket);
static void strUpper(PCHAR str);

static int authorize_control = 0;
static char *buff;

/*
* Function: adminClient
* Usage: iResult = adminClient(serverSocket);
* -------------------------------------------
* This function serves as a main function for the 
* communication with the telnet client.
*/
int adminClient(SOCKET telnet){
	buff = (char*)malloc(BUFF_BYTE);
	printAdminMesage(telnet);
	telnetCommands(telnet);
	authorize_control = 0;
	shutdown(telnet, SD_SEND);
	closesocket(telnet);

	return 0;
}

/*
* Function: telnetAuthorize
* Usage: telnetAuthorize(telnet);
* -------------------------------------
* Handles the authorization of the telnet user.
*/
static void telnetAuthorize(SOCKET telnet){
	char
		*Ppas = "\r\nPlease enter pasword: ",
		*Pmsg = "\r\nYour visit is authorized\r\n",
		*Pinp = "\r\nInvalid password\r\n",
		*Ppasword = loadServerValues().adminPassword;

	if (authorize_control == 1){
		send(telnet, Pmsg, strlen(Pmsg), 0);
	}
	else{
		send(telnet, Ppas, strlen(Ppas), 0);
		if (parseBuffer(telnet)){
			return;
		}
		
		if (strcmp(buff, Ppasword) == 0){
			authorize_control = 1;
			send(telnet, Pmsg, strlen(Pmsg), 0);
		}
		else{
			send(telnet, Pinp, strlen(Pinp), 0);
		}
	}
}

/*
* Function: telnetCommands
* Usage: telnetCommands(telnet);
* ------------------------------
* Handles the telnet commands, the commands supported by the server are:
* AUTHORIZE - Authorizes the user which unlocks the use of other commands.
* SERVER (START OR STOP) - Starts/stops the server. 
* ISACTIVE - Tells the user whether the server is active or not.
* GETLOGFILE - Reads the log file and sends it on the telnet client.
* DISCONNECT - Breaks the connection between the server and telnet client.
*/
static void telnetCommands(SOCKET telnet){
	int lenght = 0;
	char *Pactive = "\r\nServer is active\r\n",
		*Ppassive = "\r\nServer not active\r\n",
		*logMessage,
		*Perror = "\r\nInvalid command\r\n",
		*Paut = "\r\nYou are not authorized\r\n",
		*Pmsg = "\nAUTHORIZE\r\nSERVER (START OR STOP)\r\nISACTIVE\r\nGETLOGFILE\r\nDISCONNECT\r\nEnter you choice of comand: ";

	while (TRUE){
		send(telnet, Pmsg, strlen(Pmsg), 0);
		// Parse the message sent from the telnet client
		if (parseBuffer(telnet)){
			break;
		}
		strUpper(buff);

		if (strcmp(buff, "AUTHORIZE") == 0){
			telnetAuthorize(telnet);
		}
		else if (strcmp(buff, "ISACTIVE") == 0){
			if (authorize_control){
				if (isServerActive()){
					send(telnet, Pactive, strlen(Pactive), 0);
				}
				else{
					send(telnet, Ppassive, strlen(Ppassive), 0);
				}
			}
			else{
				send(telnet, Paut, strlen(Paut), 0);
			}
		}
		else if (strcmp(buff, "GETLOGFILE") == 0){
			if (authorize_control){
				getFullLogFile(&lenght, &logMessage);
				send(telnet, logMessage, lenght, 0);
				ZeroMemory(logMessage, lenght);
			}
			else{
				send(telnet, Paut, strlen(Paut), 0);
			}
		}
		else if (strcmp(buff, "SERVER START") == 0){
			if (authorize_control){
				startServer();
				send(telnet, "\r\nServer was started successfully\r\n", 35, 0);
			}
			else{
				send(telnet, Paut, strlen(Paut), 0);
			}
		}
		else if (strcmp(buff, "SERVER STOP") == 0){
			if (authorize_control){
				stopServer();
				send(telnet, "\r\nServer was stopped successfully\r\n", 35, 0);
			}
			else{
				send(telnet, Paut, strlen(Paut), 0);
			}
		}
		else if (strcmp(buff, "DISCONNECT") == 0){
			break;
		}
		else
			send(telnet, Perror, strlen(Perror), 0);

	}

}

/*
* Function: printAdminMessage
* Usage: printAdminMessage(telnet);
* ----------------------------------
* Sends the intro message to the telnet client.
*/
static void printAdminMesage(SOCKET telnet){
	char *Pmes = "Welcome to Dkom3 admin for server\r\n";
	send(telnet, Pmes, strlen(Pmes), 0);
}

/*
* Function: parseBuffer(telnet)
* Usage: if(parseBuffer(telnet))...
* ---------------------------------
* Parses the incomming message at the argument socket,
* and stores the full message in the static buff variable.
* This function is useful since different telnet clients may send
* messages in different formats. The function returns FALSE when
* a CR has been received. 
* If the user exits the telnet client while this function is still running,
* the function returns TRUE.
*/
static BOOL parseBuffer(SOCKET socket){
	int iRecvResult;
	char ch[BUFF_BYTE];

	ZeroMemory(buff, BUFF_BYTE);
	while (TRUE){
		ZeroMemory(ch, BUFF_BYTE);
		iRecvResult = recv(socket, ch, BUFF_BYTE, 0);
		if (iRecvResult <= 0){
			return SOCKET_ERROR;
		}
		else if (ch[0] == '\r'){
			return FALSE;
		}
		else{
			if (iRecvResult == 1){
				strcat_s(buff, BUFF_BYTE, ch);
			}
			else{
				strcpy_s(buff, BUFF_BYTE, ch);
			}
		}
	}

	return TRUE;
}

/*
* Function: strUpper
* Usage: strUpper(buff);
* -----------------------
* Converts the argument string into upper case.
*/
void strUpper(PCHAR str){
	while (*str++ = toupper(*str)){};
}